import json

from flask import Blueprint, jsonify, request, send_from_directory
import pandas as pd
from datetime import datetime, timedelta
import os
import logging

from app.iot_mqtt.iot_funciton import ai_queue
from app import db
from app.models import Message, Device, DeviceShadowData, DeviceCommand
from app.routes.conversations import queue_lock
from app.Ai_analyze.ai_function import extract_json_from_string

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

bp_cost = Blueprint('cost', __name__)

# 使用绝对路径
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
EV_CHARGING_CSV = os.path.join(BASE_DIR, 'document\\ev_charging.csv')
print(BASE_DIR)

# 缓存电价数据
price_data = None

# 控制模式（默认 AI 控制）
control_mode = 'ai'


def load_price_data():
    global price_data
    try:
        if not os.path.exists(EV_CHARGING_CSV):
            logger.error(f"电价文件未找到: {EV_CHARGING_CSV}")
            raise FileNotFoundError(f"电价文件未找到: {EV_CHARGING_CSV}")

        df = pd.read_csv(EV_CHARGING_CSV, encoding='utf-8')
        price_data = [
            {
                'period': str(row['时段']),
                'time_ranges': row['时间范围'].split(', '),
                'price': float(row['电价标准(元/千瓦时)'])
            }
            for _, row in df.iterrows()
        ]
        logger.info(f"成功加载电价文件: {EV_CHARGING_CSV}")
    except Exception as e:
        logger.error(f"加载电价文件失败: {str(e)}")
        price_data = [
            {'period': '高峰', 'time_ranges': ['11:00-14:00', '18:00-23:00'], 'price': 0.704},
            {'period': '平段', 'time_ranges': ['7:00-11:00', '14:00-18:00'], 'price': 0.604},
            {'period': '低谷', 'time_ranges': ['23:00-次日7:00'], 'price': 0.504}
        ]
        logger.info("使用默认电价数据")


@bp_cost.route('/cost', methods=['GET'])
def serve_cost_page():
    try:
        return send_from_directory(os.path.join(BASE_DIR, 'templates'), 'cost.html')
    except Exception as e:
        logger.error(f"提供 cost.html 失败: {str(e)}")
        return jsonify({'error': '无法加载页面'}), 500


@bp_cost.route('/price/current', methods=['GET'])
def get_current_price():
    global price_data
    if price_data is None:
        load_price_data()

    try:
        now = datetime.now()
        hour = now.hour
        minute = now.minute
        current_time = hour * 60 + minute

        for period in price_data:
            for time_range in period['time_ranges']:
                start, end = time_range.split('-')
                start_hour, start_minute = map(int, start.split(':'))
                if end == '次日7:00':
                    end_hour, end_minute = 7, 0
                    end_time = (end_hour * 60 + end_minute + 24 * 60) % (24 * 60)
                else:
                    end_hour, end_minute = map(int, end.split(':'))
                    end_time = end_hour * 60 + end_minute

                start_time = start_hour * 60 + start_minute
                if end_time < start_time:
                    if current_time >= start_time or current_time < end_time:
                        return jsonify({
                            'period': period['period'],
                            'price': float(period['price']),
                            'time_range': time_range
                        })
                elif start_time <= current_time < end_time:
                    return jsonify({
                        'period': period['period'],
                        'price': float(period['price']),
                        'time_range': time_range
                    })

        logger.warning("未找到当前时段电价，使用默认高峰电价")
        return jsonify({'period': '高峰', 'price': 0.704, 'time_range': '18:00-23:00'})
    except Exception as e:
        logger.error(f"获取当前电价失败: {str(e)}")
        return jsonify({'error': '获取电价失败', 'price': 0.704}), 500


@bp_cost.route('/cost/mode', methods=['GET', 'POST'])
def manage_control_mode():
    global control_mode
    try:
        if request.method == 'POST':
            data = request.get_json()
            new_mode = data.get('mode')
            if new_mode not in ['ai', 'manual']:
                logger.error(f"无效控制模式: {new_mode}")
                return jsonify({'error': '无效控制模式'}), 400
            control_mode = new_mode
            logger.info(f"控制模式切换为: {control_mode}")
            return jsonify({'mode': control_mode})
        return jsonify({'mode': control_mode})
    except Exception as e:
        logger.error(f"处理控制模式失败: {str(e)}")
        return jsonify({'error': '处理控制模式失败'}), 500


@bp_cost.route('/cost/calculate', methods=['POST'])
def calculate_cost():
    global price_data, control_mode
    try:
        data = request.get_json()
        print(data['command'])
        command = data['command']
        print(command)
        device_id = command["paras"]["id"]
        print(device_id)
        if device_id is None:
            logger.error("未提供设备 ID")
            return jsonify({'error': '未提供设备 ID'}), 400

        device = Device.query.filter_by(id=str(device_id)).first()
        if not device:
            logger.error(f"设备 ID {device_id} 未找到")
            return jsonify({'error': '设备未找到'}), 404

        if price_data is None:
            load_price_data()

        # 获取当前电价
        current_price_response = get_current_price()
        if current_price_response.status_code != 200:
            logger.error("获取当前电价失败")
            return jsonify({'error': '获取电价失败'}), 500
        current_price = float(current_price_response.get_json()['price'])
        current_period = current_price_response.get_json()['period']

        # 获取设备最新状态作为调控前
        latest_shadow = DeviceShadowData.query.filter_by(device_id=str(device_id)).order_by(
            DeviceShadowData.timestamp.desc()).first()
        before_command = {
            'paras': {
                'gather': latest_shadow.soil > 0 if latest_shadow and latest_shadow.soil is not None else True,
                'open_fan': latest_shadow.fan if latest_shadow and latest_shadow.fan is not None else False,
                'open_water': latest_shadow.water if latest_shadow and latest_shadow.water is not None else False,
                'open_led': latest_shadow.led if latest_shadow and latest_shadow.led is not None else False,
                'id': str(device_id)
            },
            'service_id': 'Switch',
            'command_name': 'control'
        }

        # 确保传入的 command 包含所有字段
        after_command = {
            'paras': {
                'gather': command.get('paras', {}).get('gather', before_command['paras']['gather']),
                'open_fan': command.get('paras', {}).get('open_fan', before_command['paras']['open_fan']),
                'open_water': command.get('paras', {}).get('open_water', before_command['paras']['open_water']),
                'open_led': command.get('paras', {}).get('open_led', before_command['paras']['open_led']),
                'id': str(device_id)
            },
            'service_id': command.get('service_id', 'Switch'),
            'command_name': command.get('command_name', 'control')
        }

        def calc_power_cost(cmd, price):
            rgb_power = (cmd['paras']['open_led'] or False) * 60  # LED 功耗 60W
            fan_power = (cmd['paras']['open_fan'] or False) * 50  # 风扇功耗 50W
            water_power = (cmd['paras']['open_water'] or False) * 100  # 水泵功耗 100W
            total_power = rgb_power + fan_power + water_power
            cost = (total_power * price) / 1000  # 转换为千瓦时成本
            return total_power, cost

        before_power, before_cost = calc_power_cost(before_command, current_price)
        after_power, after_cost = calc_power_cost(after_command, current_price)

        logger.info(f"成本计算 - 设备 {device_id}, 调控前功耗: {before_power}W, 成本: {before_cost:.4f}元, "
                    f"调控后功耗: {after_power}W, 成本: {after_cost:.4f}元, 模式: {control_mode}")

        return jsonify({
            'before': {
                'power': before_power,
                'cost': round(before_cost, 4)
            },
            'after': {
                'power': after_power,
                'cost': round(after_cost, 4)
            },
            'mode': control_mode,
            'period': current_period
        })
    except Exception as e:
        logger.error(f"计算成本失败: {str(e)}")
        return jsonify({'error': f'计算成本失败: {str(e)}'}), 500

@bp_cost.route('/command/latest', methods=['GET'])
def get_latest_command():
    global control_mode
    default_command = {
        'paras': {
            'gather': True,
            'open_fan': True,
            'open_water': True,
            'open_led': True,
            'led_red': 100,
            'led_blue': 100,
            'led_green': 100,
            'id': '1'  # 默认设备 ID
        },
        'service_id': 'Switch',
        'command_name': 'control'
    }
    try:
        device_id = request.args.get('device_id', '1')  # 从查询参数获取设备 ID，默认为 '1'
        latest_command = DeviceCommand.query.filter_by(device_id=str(device_id), status='completed').order_by(
            DeviceCommand.created_at.desc()).first()

        if not latest_command:
            logger.warning(f"设备 {device_id} 无可用命令，返回默认命令")
            return jsonify({'command': default_command, 'mode': control_mode})

        command = {
            'paras': {
                'gather': latest_command.command_data.get('gather', True),
                'open_fan': latest_command.command_data.get('open_fan', False),
                'open_water': latest_command.command_data.get('open_water', False),
                'open_led': latest_command.command_data.get('open_led', False),
                'led_red': latest_command.command_data.get('led_red', 100),
                'led_green': latest_command.command_data.get('led_green', 100),
                'led_blue': latest_command.command_data.get('led_blue', 100),
                'id': str(device_id)
            },
            'service_id': 'Switch',
            'command_name': 'control'
        }

        logger.info(f"获取最新命令 - 设备 {device_id}, 命令: {json.dumps(command, ensure_ascii=False)}")
        return jsonify({'command': command, 'mode': control_mode})

    except Exception as e:
        logger.error(f"获取最新命令失败: {str(e)}")
        return jsonify({'command': default_command, 'mode': control_mode, 'error': str(e)}), 500


@bp_cost.route('/cost/sensor/update', methods=['POST'], endpoint='cost_sensor_update')
def update_sensor_data():
    try:
        data = request.get_json()
        if not data or not all(k in data for k in ['light', 'temperature', 'humidity']):
            logger.error("无效传感器数据")
            return jsonify({'error': '无效传感器数据'}), 400

        with queue_lock:
            ai_queue.append(data)
        logger.info(f"传感器数据已更新: {data}")
        return jsonify({'success': True})
    except Exception as e:
        logger.error(f"更新传感器数据失败: {str(e)}")
        return jsonify({'error': '更新传感器数据失败'}), 500


@bp_cost.route("device/history", methods=["GET"])
def get_device_history():
    """获取设备历史数据"""
    device_id = request.args.get('device_id')
    range = request.args.get('range', '1h')
    # from app import create_app
    from main import app
    current_app = app
    # current_app = create_app()
    with current_app.app_context():
        device = Device.query.filter_by(id=device_id).first()
        if not device:
            return jsonify({'error': '设备未找到'}), 404

        now = datetime.now()
        if range == '1h':
            start = now - timedelta(hours=1)
        elif range == '24h':
            start = now - timedelta(days=1)
        else:  # 7d
            start = now - timedelta(days=7)

        data = DeviceShadowData.query.filter_by(device_id=device.id).filter(
            DeviceShadowData.timestamp >= start
        ).order_by(DeviceShadowData.timestamp.asc()).all()

        return jsonify({
            'timestamps': [d.timestamp.strftime('%Y-%m-%d %H:%M:%S') for d in data],
            'temperature': [d.tem or 0.0 for d in data],
            'humidity': [d.hum or 0.0 for d in data],
            'light': [d.light or 0.0 for d in data],
            'soil': [d.soil or 0.0 for d in data],
            'ph': [d.ph or 0.0 for d in data],
            'uv': [d.uv or 0.0 for d in data],
            'rain': [d.rain or 0.0 for d in data],
        })
